package cn.iocoder.an.module.business.service.equipmentcheckconfig;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.an.framework.common.util.business.CreateKeepNo;
import cn.iocoder.an.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.an.module.business.controller.admin.equipmentchecktype.vo.EquipmentCheckTypeSaveReqVO;
import cn.iocoder.an.module.business.controller.admin.equipmentkeepconfig.vo.BindSaveOrDeleteVO;
import cn.iocoder.an.module.business.controller.admin.equipmentkeepsettingtype.vo.EquipmentKeepSettingTypeSaveReqVO;
import cn.iocoder.an.module.business.dal.dataobject.equipmentkeepconfig.EquipmentKeepConfigDO;
import cn.iocoder.an.module.business.dal.dataobject.equipmentkeepsettingtype.EquipmentKeepSettingTypeDO;
import cn.iocoder.an.module.business.dal.dataobject.equipmentmanage.EquipmentManageDO;
import cn.iocoder.an.module.business.dal.dataobject.equipmnetkeepwait.EquipmnetKeepWaitDO;
import cn.iocoder.an.module.business.enums.KeepStatusEnum;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.iocoder.an.module.business.controller.admin.equipmentcheckconfig.vo.*;
import cn.iocoder.an.module.business.dal.dataobject.equipmentcheckconfig.EquipmentCheckConfigDO;
import cn.iocoder.an.framework.common.pojo.PageResult;
import cn.iocoder.an.framework.common.pojo.PageParam;
import cn.iocoder.an.framework.common.util.object.BeanUtils;

import cn.iocoder.an.module.business.dal.mysql.equipmentcheckconfig.EquipmentCheckConfigMapper;

import static cn.iocoder.an.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.an.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.an.module.business.enums.ErrorCodeConstants.*;

/**
 * 设备点检配置 Service 实现类
 *
 * @author zzy
 */
@Service
@Validated
public class EquipmentCheckConfigServiceImpl implements EquipmentCheckConfigService {

    @Resource
    private EquipmentCheckConfigMapper equipmentCheckConfigMapper;

    @Override
    public Long createEquipmentCheckConfig(EquipmentCheckConfigSaveReqVO createReqVO) {
        // 插入
        EquipmentCheckConfigDO equipmentCheckConfig = BeanUtils.toBean(createReqVO, EquipmentCheckConfigDO.class);
        equipmentCheckConfigMapper.insert(equipmentCheckConfig);

        // 返回
        return equipmentCheckConfig.getId();
    }

    @Override
    public void updateEquipmentCheckConfig(EquipmentCheckConfigSaveReqVO updateReqVO) {
        // 校验存在
        validateEquipmentCheckConfigExists(updateReqVO.getId());
        // 更新
        EquipmentCheckConfigDO updateObj = BeanUtils.toBean(updateReqVO, EquipmentCheckConfigDO.class);
        equipmentCheckConfigMapper.updateById(updateObj);
    }

    @Override
    public void deleteEquipmentCheckConfig(Long id) {
        // 校验存在
        validateEquipmentCheckConfigExists(id);
        // 删除
        equipmentCheckConfigMapper.deleteById(id);
    }

    @Override
        public void deleteEquipmentCheckConfigListByIds(List<Long> ids) {
        // 删除
        equipmentCheckConfigMapper.deleteByIds(ids);
        }


    private void validateEquipmentCheckConfigExists(Long id) {
        if (equipmentCheckConfigMapper.selectById(id) == null) {
            throw exception(EQUIPMENT_CHECK_CONFIG_NOT_EXISTS);
        }
    }

    @Override
    public EquipmentCheckConfigDO getEquipmentCheckConfig(Long id) {
        return equipmentCheckConfigMapper.selectById(id);
    }

    @Override
    public PageResult<EquipmentCheckConfigDO> getEquipmentCheckConfigPage(EquipmentCheckConfigPageReqVO pageReqVO) {
        return equipmentCheckConfigMapper.selectPage(pageReqVO);
    }

    @Override
    public int batchEquipmentCheckConfig(BindSaveOrDeleteCheckVO vo) {
        //操作类型 绑定或解绑
        String type = vo.getType();
        //当前是按分类配置(1) 还是按设备配置(2)
        Integer currentType = vo.getCurrentType();
        //分类ID或设备ID
        Long currentTargetId = vo.getCurrentTargetId();
        List<EquipmentCheckTypeSaveReqVO> reqVOList = vo.getReqVOList();
        int count = 0;
        if ("delete".equals(type)) {
            //解绑的数据
            for (EquipmentCheckTypeSaveReqVO reqVO : reqVOList) {
                LambdaQueryWrapperX<EquipmentCheckConfigDO> configWrapper = new LambdaQueryWrapperX<>();
                configWrapper.eq(EquipmentCheckConfigDO::getCheckTypeId, reqVO.getId());
                configWrapper.eq(EquipmentCheckConfigDO::getConfigType, currentType);
                configWrapper.eq(EquipmentCheckConfigDO::getTargetId, currentTargetId);
                equipmentCheckConfigMapper.delete(configWrapper);
//                deleteWaitKeepEquipmentData(currentType, currentTargetId, reqVO.getId());
                count++;
            }

        } else if ("add".equals(type)) {
            //新增的绑定的数据
            for (EquipmentCheckTypeSaveReqVO reqVO : reqVOList) {
                //configType为1按类型 2按设备
                EquipmentCheckConfigDO checkConfigDO = new EquipmentCheckConfigDO();
                checkConfigDO.setConfigType(currentType);
                checkConfigDO.setTargetId(currentTargetId);
                checkConfigDO.setCheckTypeId(reqVO.getId());
                equipmentCheckConfigMapper.insert(checkConfigDO);
//                createWaitKeepEquipmentData(currentType, currentTargetId, reqVO.getId());
                count++;
            }

            //执行一次定时任务
            try {
//                warningMessageSendJob.execute("");
            } catch (Exception e) {
                System.out.printf(e.getMessage());
            }

        }

        return count;
    }


    //如果移除绑定 除了状态为已完成的待保养设备  其余都删除
    /*
    public void deleteWaitKeepEquipmentData(Integer currentType, Long targetId, Long itemId) {
        if (currentType == 1) {
            //1.查询该分类下的所有设备
            LambdaQueryWrapperX<EquipmentManageDO> wrapper = new LambdaQueryWrapperX<>();
            wrapper.eq(EquipmentManageDO::getEquipmentClassify, targetId);
            List<EquipmentManageDO> equipmentList = equipmentManageMapper.selectList(wrapper);
            List<Long> equipmentIDds = equipmentList.stream()
                    .map(EquipmentManageDO::getId)
                    .collect(Collectors.toList());

            if (CollectionUtils.isEmpty(equipmentIDds)) return;

            //2.查询除了已完成所有的待保养设备列表
            LambdaQueryWrapperX<EquipmnetKeepWaitDO> waitWrapper = new LambdaQueryWrapperX<>();
            waitWrapper.ne(EquipmnetKeepWaitDO::getStatus, KeepStatusEnum.COMPLETE.getKeepStatus());
            waitWrapper.in(EquipmnetKeepWaitDO::getEquipmentId, equipmentIDds);
            waitWrapper.eq(EquipmnetKeepWaitDO::getItemId, itemId);
            int delete = equipmnetKeepWaitMapper.delete(waitWrapper);
            System.out.printf("已删除:" + delete + "条数据");
        } else if (currentType == 2) {
            //1.查询除了已完成所有的待保养设备列表
            LambdaQueryWrapperX<EquipmnetKeepWaitDO> waitWrapper = new LambdaQueryWrapperX<>();
            waitWrapper.ne(EquipmnetKeepWaitDO::getStatus, KeepStatusEnum.COMPLETE.getKeepStatus());
            waitWrapper.in(EquipmnetKeepWaitDO::getEquipmentId, targetId);
            waitWrapper.eq(EquipmnetKeepWaitDO::getItemId, itemId);
            int delete = equipmnetKeepWaitMapper.delete(waitWrapper);
            System.out.printf("已删除:" + delete + "条数据");
        }

    }


     */

    /*
    @Transactional(rollbackFor = Exception.class)
    public void createWaitKeepEquipmentData(Integer currentType, Long targetId, Long itemId) {
        if (currentType == null || targetId == null || itemId == null) {
            return;
        }

        // 当前年月，用于单号前缀
        String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
        String prefix = CreateKeepNo.PREFIX; // "BY"
        String prefixPattern = prefix + yearMonth; // "BY202508"

        // 🔐 分布式锁 key：按月隔离，不同月不互斥
        String lockKey = "lock:keep_no:" + prefixPattern;
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 获取锁（最多等待10秒，持有30秒自动释放）
            boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS);
            if (!isLocked) {
                throw new RuntimeException("获取分布式锁失败，无法生成唯一单号");
            }

            // ✅ 在锁内查询当前最大单号
            String maxKeepNo = equipmnetKeepWaitMapper.findMaxKeepNo(prefixPattern);

            // ✅ 生成下一个基础单号（如 BY2025080001）
            String nextBaseNo = CreateKeepNo.generateNextCode(maxKeepNo);

            List<EquipmnetKeepWaitDO> saveList = new ArrayList<>();

            if (currentType == 1) {
                //1. 按分类：批量设备 currentType等于1为按分类 则targetId为分类的ID 需要查询该分类下的所有有“最近一次保养时间”的所有设备
                LambdaQueryWrapperX<EquipmentManageDO> wrapper = new LambdaQueryWrapperX<>();
                wrapper.eq(EquipmentManageDO::getEquipmentClassify, targetId);
                wrapper.isNotNull(EquipmentManageDO::getMaintainDatetime);
                List<EquipmentManageDO> equipmentList = equipmentManageMapper.selectList(wrapper);

                if (equipmentList.isEmpty()) return;

                //2.查询是否已经生成过待保养记录? 无需排重了 因为解绑的时候会删除的。

                EquipmentKeepSettingTypeDO setting = equipmentKeepSettingTypeService.getEquipmentKeepSettingType(itemId);
                Integer cycle = setting.getCycle();

                //3.生成对应的待保养设备数据  为每个设备生成一个递增的单号
                String currentNo = nextBaseNo;
                for (EquipmentManageDO equipment : equipmentList) {

                    EquipmnetKeepWaitDO save = new EquipmnetKeepWaitDO();

                    save.setKeepNo(currentNo); // 第一个设备用 baseNo
                    save.setItemId(itemId);//保养项ID
                    save.setEquipmentId(equipment.getId());//设备ID
                    save.setStatus(KeepStatusEnum.WAIT.getKeepStatus());//状态 新增设置为待派工
                    save.setEquipmentName(equipment.getEquipmentName());
                    //最近一次保养时间

                    if (equipment.getMaintainDatetime() != null) {
                        LocalDate lastDate = equipment.getMaintainDatetime().toLocalDate();
                        save.setPlanDate(lastDate.plusDays(setting.getCycle()));
                    } else {
                        save.setPlanDate(LocalDate.now().plusDays(setting.getCycle()));
                    }
                    saveList.add(save);

                    // 生成下一个单号（BY202508001 → BY202508002）
                    currentNo = CreateKeepNo.generateNextCode(currentNo);
                }

            } else if (currentType == 2) {
                // 按设备：单个设备
                EquipmentManageDO equipment = equipmentManageMapper.selectById(targetId);
                if (equipment == null) {
                    return;
                }

                EquipmnetKeepWaitDO save = new EquipmnetKeepWaitDO();
                save.setKeepNo(nextBaseNo); // 直接使用生成的第一个号
                save.setItemId(itemId);
                save.setEquipmentId(equipment.getId());
                save.setStatus(KeepStatusEnum.WAIT.getKeepStatus());
                save.setEquipmentName(equipment.getEquipmentName());
                EquipmentKeepSettingTypeDO setting = equipmentKeepSettingTypeService.getEquipmentKeepSettingType(itemId);
                if (equipment.getMaintainDatetime() != null) {
                    LocalDate lastDate = equipment.getMaintainDatetime().toLocalDate();
                    save.setPlanDate(lastDate.plusDays(setting.getCycle()));
                } else {
                    save.setPlanDate(LocalDate.now().plusDays(setting.getCycle()));
                }

                saveList.add(save);
            }

            // 批量插入（事务内）
            if (!saveList.isEmpty()) {
                equipmnetKeepWaitMapper.insertBatch(saveList);
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("生成单号时被中断", e);
        } catch (Exception e) {
            throw new RuntimeException("生成保养任务失败: " + e.getMessage(), e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


     */


}